using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace FrameWork.Source.Animation_Classes
{
    class CAnimation
    {
        /// <summary>
        /// ID of this Animation
        /// </summary>
        public ulong m_UID { get; private set; }

        /// <summary>
        /// Name of this animation
        /// </summary>
        public string m_strName { get; private set; }

        /// <summary>
        /// Get or set the current frame for this animation
        /// </summary>
        public int m_iCurrFrame { get; set; }

        /// <summary>
        /// Get or set start frame for this animation
        /// </summary>
        public int m_iStartFrame { get; set; }

        /// <summary>
        /// Get or set end frame for this animation
        /// </summary>
        public int m_iEndFrame { get; set; }

        /// <summary>
        /// Get or set looping frame index for this animation
        /// </summary>
        public int m_iLoopFrame { get; set; }

        /// <summary>
        /// Get or set action speed for this object
        /// </summary>
        public float m_fActionSpeed { get; set; }

        /// <summary>
        /// If this animation run forward or backward ( true = backward , false = forward ).
        /// Note : false is default;
        /// </summary>
        static public bool m_isReverse { get; set; }

        /// <summary>
        /// Local time of this animation
        /// If local time >= action speed , then we update our new frame
        /// </summary>
        private float m_fLocalTime;

        /// <summary>
        /// List sequence frame if frame update like ( 3 -> 2 -> 5 -> .. )
        /// </summary>
        private int[] m_pListFrame;

        /// <summary>
        /// Current sequence frame index
        /// </summary>
        private int m_iCurrIndex;

        /// <summary>
        /// Is we update our sequence frame or normal
        /// </summary>
        private bool m_isSequence;

        /// <summary>
        /// Constructor for this class
        /// </summary>
        public CAnimation()
        {
            m_iCurrFrame = 0;
            m_iStartFrame = 0;
            m_iEndFrame = 0;
            m_iLoopFrame = 0;
            m_fActionSpeed = 0.0f;
            m_fLocalTime = 0.0f;
            m_isReverse = false;
            m_pListFrame = null;
            m_isSequence = false;
            m_iCurrIndex = 0;
        }


        /// <summary>
        /// Create new animation 
        /// </summary>
        /// <param name="id">ID or animation index</param>
        /// <param name="startFrame">Start frame index of this animation</param>
        /// <param name="endFrame">End frame index of this animation</param>
        /// /// <param name="loopFrame">Looping frame index of this animation</param>
        /// <param name="actionSpeed">Action speed of this animation</param>
        public void createAnimation(ulong id, int startFrame, int endFrame, int loopFrame , float actionSpeed)
        {
            m_UID = id;
            m_iStartFrame = startFrame;
            m_iEndFrame = endFrame;
            m_iLoopFrame = loopFrame;
            m_fActionSpeed = actionSpeed;
            m_iCurrFrame = m_iStartFrame;
        }


        /// <summary>
        /// Create new animation
        /// </summary>
        /// <param name="name">Name of this animation</param>
        /// <param name="startFrame">Start frame index of this animation</param>
        /// <param name="endFrame">End frame index of this animation</param>
        /// <param name="loopFrame">Looping frame index of this animation</param>
        /// <param name="actionSpeed">Action speed of this animation</param>
        public void createAnimation(string name, int startFrame, int endFrame, int loopFrame, float actionSpeed)
        {
            m_strName = name;
            m_iStartFrame = startFrame;
            m_iEndFrame = endFrame;
            m_iLoopFrame = loopFrame;
            m_fActionSpeed = actionSpeed;
            m_iCurrFrame = m_iStartFrame;
        }


        
        /// <summary>
        /// Update our new frame ( only run this methods once per frame )
        /// </summary>
        /// <param name="deltaTime">A delta time</param>
        /// <param name="sourceRect">ref of image source rect for re-calculator it</param>
        /// <param name="width">Width of 1 frame</param>
        /// <param name="height">Height of 1 frame</param>
        /// <param name="numFrameInRow">Number frame in one row</param>
        public void update(float deltaTime, ref Rectangle sourceRect, int width, int height, int numFrameInRow)
        {
            m_fLocalTime += deltaTime;
            if (m_fLocalTime >= m_fActionSpeed)
            {
                if (!m_isSequence) // if normal
                {
                    if (!m_isReverse) // if we update animation forward
                        nextFrame(); 
                    else // if we update animation backward
                        previousFrame();
                }
                else // if we update animation base on sequence frame
                {
                    m_iCurrFrame = m_pListFrame[m_iCurrFrame];
                    m_iCurrIndex += 1;
                    if (m_iCurrFrame >= m_pListFrame.Length)
                        m_iCurrFrame = 0;
                }
                updateSourceRect(ref sourceRect, width, height, numFrameInRow);
                m_fLocalTime -= m_fActionSpeed;
            }
        }

        /// <summary>
        /// Set frame sequence for this animation
        /// </summary>
        /// <param name="listFrame">List sequence frame like frame 3 -> frame 2 -> frame 5 -> ...</param>
        public void setFrameSequence(int[] listFrame)
        {
            m_pListFrame = listFrame;
            m_isSequence = true;
            m_iCurrFrame = m_pListFrame[0];
        }

        /// <summary>
        /// Advanced to next frame
        /// </summary>
        private void nextFrame()
        {
            m_iCurrFrame += 1;
            if (m_iCurrFrame > m_iEndFrame)
                m_iCurrFrame = m_iLoopFrame;
        }

        /// <summary>
        /// Advanced to previous frame
        /// </summary>
        private void previousFrame()
        {
            m_iCurrFrame -= 1;
            if (m_iCurrFrame <= m_iStartFrame)
                m_iCurrFrame = 0;
        }

        /// <summary>
        /// Update our image source rect
        /// </summary>
        /// <param name="sourceRect">ref of image source rect for re-calculator it</param>
        /// <param name="width">Width of one frame</param>
        /// <param name="height">Height of one frame</param>
        /// <param name="numFrameInRow">Number frame in one row</param>
        public void updateSourceRect(ref Rectangle sourceRect, int width, int height, int numFrameInRow)
        {
            sourceRect.X = (m_iCurrFrame % numFrameInRow) * width;
            sourceRect.Y = (m_iCurrFrame / numFrameInRow) * height;
            sourceRect.Width = width;
            sourceRect.Height = height;
        }


        /// <summary>
        /// Is our animation end or not
        /// </summary>
        /// <returns>True if end , false if not</returns>
        public bool isEndAnimation()
        {
            if (m_iCurrFrame == m_iEndFrame)
                return true;

            return false;
        }

        /// <summary>
        /// Reset our animation
        /// </summary>
        public void resetAnimation()
        {
            m_iCurrFrame = m_iStartFrame;
        }
    }
}
